<?php
namespace app\api\controller;

use app\api\model\ExamPaper;
use app\api\model\ExamPaperQuestion;
use app\api\model\ExamQuestion;
use app\api\model\ExamUserPaper;
use app\api\model\ExamUserAnswer;
use think\facade\Db;
use think\facade\Request;

use app\common\controller\Frontend;

class Exam extends Frontend
{
    // 获取可用试卷列表
    public function paperList()
    {
        $list = ExamPaper::order('id desc')->field('id,title,description,duration,question_count,total_score')->select();
        return json(['code'=>1,'msg'=>'','data'=>$list]);
    }

    // 获取试卷详情（含题目）
    public function paperDetail($id)
    {
        $paper = ExamPaper::find($id);
        if(!$paper) return json(['code'=>0,'msg'=>'试卷不存在']);
        $qids = ExamPaperQuestion::where('paper_id',$id)->order('sort asc,id asc')->column('question_id');
        $questions = ExamQuestion::whereIn('id',$qids)->select();
        // 保持题目顺序
        $questions = collect($qids)->map(function($qid) use($questions){
            return $questions->where('id',$qid)->first();
        })->filter()->values();
        return json(['code'=>1,'msg'=>'','data'=>['paper'=>$paper,'questions'=>$questions]]);
    }

    // 开始考试（生成考生答卷）
    public function start($paper_id)
    {
        $user_id = $this->getUserId();
        $exist = ExamUserPaper::where(['user_id'=>$user_id,'paper_id'=>$paper_id,'status'=>'pending'])->find();
        if($exist) return json(['code'=>1,'msg'=>'已存在未完成答卷','data'=>['user_paper_id'=>$exist->id]]);
        $userPaper = ExamUserPaper::create([
            'user_id'=>$user_id,
            'paper_id'=>$paper_id,
            'status'=>'pending',
            'start_time'=>time(),
            'create_time'=>time(),
            'update_time'=>time()
        ]);
    return json(['code'=>1,'msg'=>'','data'=>['user_paper_id'=>$userPaper->id,'start_time'=>$userPaper->start_time]]);
    }

    // 提交答卷
    public function submit()
    {
        $user_id = $this->getUserId();
        $data = input('post.');
        $user_paper_id = $data['user_paper_id'] ?? 0;
        $answers = $data['answers'] ?? [];
        $userPaper = ExamUserPaper::where(['id'=>$user_paper_id,'user_id'=>$user_id])->find();
        if(!$userPaper || $userPaper->status!='pending') return json(['code'=>0,'msg'=>'无效的答卷']);
        // 检查是否超时：若存在试卷 duration（分钟）和 start_time，则超过时长禁止提交
        $paper = ExamPaper::find($userPaper->paper_id);
        if ($paper && $paper->duration && $userPaper->start_time) {
            $allowedUntil = intval($userPaper->start_time) + intval($paper->duration) * 60;
            if (time() > $allowedUntil) {
                // 标记为已结束并保存（不计分）
                $userPaper->status = 'finished';
                $userPaper->end_time = time();
                $userPaper->save();
                return json(['code'=>0,'msg'=>'考试时间已到，不能提交答卷']);
            }
        }
        // 保存答题（规范化输入，防止 stdClass 导致类型错误）
        foreach($answers as $a){
            // if client sent objects (stdClass), convert to array
            if (is_object($a)) $a = (array)$a;
            // normalize nested answer (could be array or object)
            if (isset($a['answer']) && is_object($a['answer'])) {
                $a['answer'] = json_decode(json_encode($a['answer']), true);
            }
            $questionId = isset($a['question_id']) ? (int)$a['question_id'] : 0;
            $type = isset($a['type']) ? $a['type'] : '';
            $answerField = isset($a['answer']) ? $a['answer'] : '';
            ExamUserAnswer::create([
                'user_paper_id'=>$user_paper_id,
                'question_id'=>$questionId,
                'type'=>$type,
                'answer'=>is_array($answerField) ? json_encode($answerField,JSON_UNESCAPED_UNICODE) : $answerField,
                'create_time'=>time(),
                'update_time'=>time()
            ]);
        }
        // 自动评分
        $score = 0;
        $questions = ExamPaperQuestion::where('paper_id',$userPaper->paper_id)->select();
        foreach($questions as $q){
            $question = ExamQuestion::find($q->question_id);
            $userAnswer = ExamUserAnswer::where(['user_paper_id'=>$user_paper_id,'question_id'=>$q->question_id])->find();
            if(!$question || !$userAnswer) continue;
            $autoTypes = ['single','multi','judge','blank'];
            if(in_array($question->type,$autoTypes)){
                if($this->checkAnswer($question,$userAnswer->answer)){
                    $userAnswer->score = $q->score;
                    $score += $q->score;
                }else{
                    $userAnswer->score = 0;
                }
                $userAnswer->is_reviewed = 1;
                $userAnswer->save();
            }
        }
        $userPaper->score = $score;
        $userPaper->status = 'finished';
        $userPaper->end_time = time();
        $userPaper->save();
        return json(['code'=>1,'msg'=>'提交成功','data'=>['score'=>$score]]);
    }

    // 答案对比（自动评分）
    private function checkAnswer($question,$userAnswer)
    {
        // normalize options: support array of texts or associative array keyed by letters
        $options = $question->options;
        // if options came as object (stdClass), convert to array
        if (is_object($options)) {
            $options = json_decode(json_encode($options), true);
        }
        if (is_string($options)) {
            $decodedOpts = json_decode($options, true);
            if ($decodedOpts !== null) $options = $decodedOpts;
        }
        // If options is associative (e.g. ['A'=>'text']), build a flat array of texts and remember mapping
        $letterMap = null;
        if (is_array($options)) {
            $isAssoc = array_values($options) !== $options;
            if ($isAssoc) {
                $letterMap = $options; // letter => text
                $options = array_values($options);
            }
        }

        $std = $question->answer;
        // if std came as object, convert to array/string
        if (is_object($std)) {
            $std = json_decode(json_encode($std), true);
        }
        // try decode JSON answers
        if (is_string($std)) {
            $decoded = json_decode($std, true);
            if ($decoded !== null) $std = $decoded;
        }
        // helper: convert option index to letter
        $idxToLetter = function ($i) { return chr(65 + intval($i)); };

        // build standard letters
        $stdLetters = [];
        if (is_array($std)) {
            // elements may be letters or option texts
            $allLetters = true;
            foreach ($std as $it) {
                if (!is_string($it) || strlen($it) != 1 || !ctype_alpha($it)) { $allLetters = false; break; }
            }
            if ($allLetters) {
                foreach ($std as $it) $stdLetters[] = strtoupper($it);
            } else {
                // map texts to letters using options
                if (is_array($options)) {
                    foreach ($std as $val) {
                        // if we had an original letterMap, try to find key by value
                        if ($letterMap) {
                            $k = array_search($val, $letterMap, true);
                            if ($k !== false) $stdLetters[] = strtoupper($k);
                            else {
                                $pos = array_search($val, $options, true);
                                if ($pos !== false) $stdLetters[] = $idxToLetter($pos);
                            }
                        } else {
                            $pos = array_search($val, $options, true);
                            if ($pos !== false) $stdLetters[] = $idxToLetter($pos);
                        }
                    }
                }
            }
        } elseif (is_string($std)) {
            if (strpos($std, ',') !== false) {
                $parts = array_map('trim', explode(',', $std));
                foreach ($parts as $p) $stdLetters[] = $p;
            } elseif (preg_match('/^[A-Za-z]$/', $std)) {
                $stdLetters[] = strtoupper($std);
            } else {
                // single text
                if (is_array($options)) {
                    $pos = array_search($std, $options, true);
                    if ($pos !== false) $stdLetters[] = $idxToLetter($pos);
                }
            }
        }

        // normalize user answer to letters
        if (is_object($userAnswer)) {
            $userAnswer = json_decode(json_encode($userAnswer), true);
        }
        if (is_string($userAnswer)) {
            $decoded = json_decode($userAnswer, true);
            if ($decoded !== null) $userAnswer = $decoded;
        }
        $userLetters = [];
        if (is_array($userAnswer)) {
            $allLetters = true;
            foreach ($userAnswer as $it) {
                if (!is_string($it) || strlen($it) != 1 || !ctype_alpha($it)) { $allLetters = false; break; }
            }
            if ($allLetters) {
                foreach ($userAnswer as $it) $userLetters[] = strtoupper($it);
            } else {
                if (is_array($options)) {
                    foreach ($userAnswer as $val) {
                        if ($letterMap) {
                            $k = array_search($val, $letterMap, true);
                            if ($k !== false) $userLetters[] = strtoupper($k);
                            else {
                                $pos = array_search($val, $options, true);
                                if ($pos !== false) $userLetters[] = $idxToLetter($pos);
                            }
                        } else {
                            $pos = array_search($val, $options, true);
                            if ($pos !== false) $userLetters[] = $idxToLetter($pos);
                        }
                    }
                }
            }
        } elseif (is_string($userAnswer)) {
            if (strpos($userAnswer, ',') !== false) {
                $parts = array_map('trim', explode(',', $userAnswer));
                foreach ($parts as $p) $userLetters[] = strtoupper($p);
            } elseif (preg_match('/^[A-Za-z]$/', $userAnswer)) {
                $userLetters[] = strtoupper($userAnswer);
            } else {
                if (is_array($options)) {
                    if ($letterMap) {
                        $k = array_search($userAnswer, $letterMap, true);
                        if ($k !== false) $userLetters[] = strtoupper($k);
                        else {
                            $pos = array_search($userAnswer, $options, true);
                            if ($pos !== false) $userLetters[] = $idxToLetter($pos);
                        }
                    } else {
                        $pos = array_search($userAnswer, $options, true);
                        if ($pos !== false) $userLetters[] = $idxToLetter($pos);
                    }
                }
            }
        }

        // compare
        $stdLetters = array_map('strtoupper', $stdLetters);
        $userLetters = array_map('strtoupper', $userLetters);
        if ($question->type == 'multi') {
            sort($stdLetters); sort($userLetters);
            return count($stdLetters) === count($userLetters) && !array_diff($stdLetters, $userLetters);
        }
        // single/judge/blank
        if (empty($stdLetters) || empty($userLetters)) {
            // fallback to direct compare
            return $std == $userAnswer;
        }
        return $stdLetters[0] == $userLetters[0];
    }

    // 获取考试记录
    public function myPapers()
    {
        $user_id = $this->getUserId();
        $list = ExamUserPaper::where('user_id',$user_id)->order('id desc')->select();
        return json(['code'=>1,'msg'=>'','data'=>$list]);
    }

    // 获取答卷详情
    public function myPaperDetail($user_paper_id)
    {
        $user_id = $this->getUserId();
        $userPaper = ExamUserPaper::where(['id'=>$user_paper_id,'user_id'=>$user_id])->find();
        if(!$userPaper) return json(['code'=>0,'msg'=>'无效的答卷']);
        $answers = ExamUserAnswer::where('user_paper_id',$user_paper_id)->select();
        $questions = ExamPaperQuestion::where('paper_id',$userPaper->paper_id)->select();
        $qids = array_column($questions->toArray(),'question_id');
        $questionList = ExamQuestion::whereIn('id',$qids)->select();
        return json(['code'=>1,'msg'=>'','data'=>[
            'paper'=>$userPaper,
            'answers'=>$answers,
            'questions'=>$questionList
        ]]);
    }

    // 获取当前登录用户ID（示例，需结合实际登录逻辑）
    private function getUserId()
    {
        // 假设用 session('user.id')
        return session('user.id') ?: 1;
    }
}
